package com.macrounion.atv.processor;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.macrounion.atv.dto.req.ExchangeChannelReqDto;
import com.macrounion.atv.service.dto.req.ChannelReqDto;
import com.macrounion.atv.service.entity.*;
import com.macrounion.atv.service.enums.DeviceTypeEnum;
import com.macrounion.atv.service.service.*;
import com.macrounion.atv.service.utils.CalculatorUtils;
import com.macrounion.atv.socket.SendConnectionProcessor;

import com.macrounion.base.service.dto.PageRespDto;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.macrounion.atv.cache.ChannelCache;
import com.macrounion.atv.cache.CurrentDataCache;
import com.macrounion.atv.cache.DeviceCache;
import com.macrounion.atv.cache.VirtualChannelCache;
import com.macrounion.atv.dto.req.BatchChannelReqDto;
import com.macrounion.atv.service.entity.ext.DeviceExt;
import com.macrounion.atv.utils.BeanMapUtils;
import com.macrounion.base.processor.BaseProcessor;
import com.macrounion.base.service.dto.BaseRespDto;
import com.macrounion.base.service.exception.BusinessException;
import com.macrounion.base.service.utils.BigDecimalUtil;
import com.macrounion.device.server.out.dto.CMSAlarmOutDto.Command;
import com.macrounion.device.server.out.dto.DataViewAlarmOutDto;

import org.apache.commons.lang3.StringUtils;

@Component
public class ChannelProcessor extends BaseProcessor<Channel, Channel, ChannelService, Channel> {

	@Autowired
	private VirtualChannelCache virtualChannelCache;
	@Autowired
	private CurrentDataProcessor currentDataProcessor;
	@Autowired
	private ChannelCache channelCache;
	@Autowired
	private DeviceProcessor deviceProcessor;
	@Autowired
	private ChannelService channelService;
	@Autowired
	private CurrentDataCache currentDataCache;
	@Autowired
	private VirtualChannelService virtualService;
	@Autowired
	private SettingsProcessor settingsProcessor;
	@Autowired
	private DeviceService deviceService;
	@Autowired
	private SendConnectionProcessor sendConnectionProcessor;
	@Autowired
	private DeviceCache deviceCache;
	@Autowired
	private ProtocolService protocolService;

	/**
	 * 从新计算通道值
	 * @param c
	 * @param value
	 * @return
	 */
	public String getVaule(Channel c, String value) {
		//虚拟通道不计算
		if(c==null||!StringUtils.isEmpty(c.getVirtualId()))
			return value;
		String v = value.trim();
		if(c.getXishu() != null) {
			//系数值
			try {
				double d = BigDecimalUtil.mul(c.getXishu().doubleValue(), new Double(v));
//				v = Double.toString(BigDecimalUtil.mul(c.getXishu().doubleValue(), new Double(v)));

				java.text.NumberFormat NF = java.text.NumberFormat.getInstance();
				//设置数的小数部分所允许的最大位数，避免小数位被舍掉
				NF.setMaximumFractionDigits(15);
				//设置数的小数部分所允许的最小位数，避免小数位有多余的0
				NF.setMinimumFractionDigits(0);
				//去掉科学计数法显示，避免显示为111,111,111,111
				NF.setGroupingUsed(false);
				v =  NF.format(d);
			} catch (Exception e) {	
//				e.printStackTrace();
			}
		}
		//翻译
		v = translateValue(c.getTranslate(),v);
		return v;
	}
	
	/**
	 * 翻译
	 * @return
	 */
	public String translateValue(String translateStr,String value) {
		if(value != null)
			value = value.replace(",", "").replace("\\|", "");
		if(!StringUtils.isEmpty(translateStr)) {
			String[] ss = translateStr.split(",");
			for (int i = 0; i < ss.length; i++) {
				try {
					String[] vv = ss[i].split("\\|");
					if(value.equals(vv[0]))
						return vv[1];
				} catch (Exception e) {
					return value;
				}
			}
		}
		return value;
	}
	
	/**
	 * 计算涉及到此通道的虚拟通道的值
	 * @param device
	 * @param c
	 */
	public void saveVirtual(Device device, Channel c) {
		List<VirtualChannel> vs = virtualChannelCache.getFromCache(device.getDeviceCode(), c.getChannelCode());
		if(CollectionUtils.isEmpty(vs))
			return;
		vs.forEach(vir->{
			Channel channel = channelCache.getChannel(vir.getDeviceId(), vir.getChannelCode());
			Device d = deviceProcessor.findById(vir.getDeviceId());
			if(channel != null && d!= null) {
				CurrentData data = new CurrentData();
				data.setId(UUID.randomUUID().toString());
				data.setChannelCode(channel.getChannelCode());
				data.setChannelId(channel.getId());
				data.setCreatedTime(new Date());
				data.setDeviceCode(d.getDeviceCode());
				data.setDeviceId(d.getId());
				String virValue = getVirValue(vir,c);
				data.setShowValue(virValue);
				data.setSpotId(d.getSpotId());
				data.setUnit(channel.getUnit());
				data.setValues(virValue);
				data.setAlarm(getAlarm(channel, virValue));
				sendAlarmToItu(d,channel,data);
				currentDataProcessor.saveDataFromSnmp(d.getId(), Arrays.asList(data),"virdata"+d.getId()+data.getChannelCode());
			}
		});
	}

	/**
	 * 计算虚拟通道值
	 * @param vir
	 * @param value
	 * @param c --当前变值通道
	 * @return
	 */
	private String getVirValue(VirtualChannel vir, Channel c) {
		Device d = deviceProcessor.findById(c.getDeviceId());
		//单通道等值（虚拟通道=此通道）
		if(vir.getFx().trim().toUpperCase().equals(channelService.getFxKey(d.getDeviceCode(),c.getChannelCode()))) {
			CurrentData cd = currentDataCache.getCurrentdatadetails(d.getDeviceCode(), c.getChannelCode());
			return cd ==null?null:cd.getShowValue();
		}
		Map<String,Double> channelValues = new HashMap<String,Double>();
		List<String> keys = getFullCodesByFx(vir.getFx());
		keys.forEach(k->{
			try {
//				String[] codes = k.split("_");
				CurrentData cd = currentDataCache.getCurrentdatadetails(k.substring(0,k.lastIndexOf("_")), k.substring(k.lastIndexOf("_")+1));
				channelValues.put(k, Double.parseDouble(cd.getShowValue()));
			} catch (Exception e) {
				//公式不正确或存在开关量通道
			}
		});
		try {
			return CalculatorUtils.getCalculate(vir.getFx(), channelValues);
		} catch (Exception e) {
			return "-";
		}
	}

	public List<String> getFullCodesByFx(String fx) {
		Pattern p = Pattern.compile("([c|C]\\(.*?\\))");
        Matcher m = p.matcher(fx.replace(" ", ""));
        List<String> resp = Lists.newArrayList();
        while (m.find()) {
            String str = m.group(1);
            resp.add(str.replace("c(", "").replace("C(", "").replace(")", ""));
        }
		return resp;
	}


    /**
     * 设备转译数值
     * @param channel
     * @return
     */
    public int updateTranslate(Channel channel){
        int m= service.updateTranslate(channel);
        Channel c=service.findById(channel.getId());
        channelCache.saveCache(c);
        return m;
    }


    /**
     * 置换通道号
     * @param channel
     * @return
     */
    @Transactional
    public synchronized BaseRespDto<Boolean> exchangeChannel(ExchangeChannelReqDto channel){
        BaseRespDto<Boolean> resp=new BaseRespDto<Boolean>();
        if(channel==null || StringUtils.isEmpty(channel.getId()) ||
				StringUtils.isEmpty(channel.getChannelCode()) || StringUtils.isEmpty(channel.getNewChannelCode()) )
            throw new BusinessException(201,"参数错误");

        Channel existChannel=service.getByDeviceIdandChannelCode(channel.getDeviceId(),channel.getNewChannelCode());

        VirtualChannel virtualChannel = virtualService.getVirtual(channel.getDeviceId(),channel.getNewChannelCode());
        if(virtualChannel!=null)
            throw new BusinessException(202,"该通道号已被虚拟通道占用，请重新输入通道号");


        if(existChannel ==null && virtualChannel==null){
            //直接修改通道号
			channel.setChannelCode(channel.getNewChannelCode());
            service.updateChannelCode(channel);
            Channel updatedChannel=new Channel();
			BeanUtils.copyProperties(channel,updatedChannel);
			channelCache.saveCache(updatedChannel);
        }else {
            //置换通道号
			String oldChannelCode=channel.getChannelCode();
			channelCache.removeCache(channel.getDeviceId(),oldChannelCode);

            existChannel.setChannelCode("*****");
            service.updateChannelCode(existChannel);

			channel.setChannelCode(channel.getNewChannelCode());
            service.updateChannelCode(channel);

            existChannel.setChannelCode(oldChannelCode);
            service.updateChannelCode(existChannel);
        }
        resp.setData(true);
        return resp;
    }

    /**
     * 批量修改
     * @param batchChannelReqDto
     * @return
     */
    @Transactional
    public BaseRespDto<Boolean> batchSaveChannel(BatchChannelReqDto batchChannelReqDto){
        BaseRespDto<Boolean> resp=new BaseRespDto<Boolean>();

        if(batchChannelReqDto==null)
            throw new BusinessException(201,"参数错误");

		if(!batchChannelReqDto.isUpdateNull())
			throw new BusinessException(202,"请选择需要更新的参数！");

		if(CollectionUtils.isEmpty(batchChannelReqDto.getIds()))
			throw new BusinessException(203,"请选择需要更新的通道！");

        List<Channel> channelList= Lists.newArrayList();

        //删除缓存
		channelList=service.getChannelListByIds(batchChannelReqDto.getIds());
		if(!CollectionUtils.isEmpty(channelList)){
			channelList.forEach(p->{
				channelCache.removeCache(p.getDeviceId(),p.getChannelCode());
			});
		}



		List<String> virtualIds=Lists.newArrayList();
		List<String> protocolIds=Lists.newArrayList();
		if(!CollectionUtils.isEmpty(channelList)){
			for(Channel channel: channelList){
				String id=batchChannelReqDto.getIds().stream().filter(p->p.equals(channel.getId())).findFirst().orElse(null);
				if(!StringUtils.isEmpty(channel.getVirtualId()) && id!=null)
					virtualIds.add(id);
				else if(StringUtils.isEmpty(channel.getVirtualId()) && id!=null)
					protocolIds.add(id);
			}
		}

		//更新虚拟通道
		if(!CollectionUtils.isEmpty(virtualIds)){
			BatchChannelReqDto virReqDto=new BatchChannelReqDto();
			BeanUtils.copyProperties(batchChannelReqDto,virReqDto);
			virReqDto.setYuansu(null);
			virReqDto.setIds(virtualIds);
			batchSave(virReqDto);
		}

		//更新协议通道
		if(!CollectionUtils.isEmpty(protocolIds)){
			batchChannelReqDto.setIds(protocolIds);
			batchSave(batchChannelReqDto);
		}


//        //修改虚拟通道中的单位，元素
//		List<String> virtualIds=channelList.stream()
//				.filter(p-> !StringUtils.isEmpty(p.getVirtualId()))
//				.map(Channel::getVirtualId)
//				.collect(Collectors.toList());
//		if(!CollectionUtils.isEmpty(virtualIds) &&
//				(!StringUtils.isEmpty(batchChannelReqDto.getYuansu()) || !StringUtils.isEmpty(batchChannelReqDto.getUnit()))){
//			HashMap<String,Object> mapVirtual=new HashMap<>();
//			mapVirtual.put("ids",virtualIds);
//			mapVirtual.put("unit",batchChannelReqDto.getUnit());
//			mapVirtual.put("yuansu",batchChannelReqDto.getYuansu());
//			virtualService.batchUpdate(mapVirtual);
//		}

        return resp;
    }

    public void batchSave(BatchChannelReqDto reqDto){
		if(reqDto.isUpdateNull()){
			HashMap<String,Object> mapChannel=new HashMap<>();
			mapChannel= BeanMapUtils.beanToMap(reqDto);
			service.batchUpdate(mapChannel);
		}
	}


	/**
	 * 清空列表
	 * @param deviceId
	 * @return
	 */
	@Transactional
    public boolean clearChannelByDeviceId(String deviceId){
		delCacheChannel(deviceId);//删除缓存
        int c=service.clearChannelByDeviceId(deviceId);
        return true;
    }

    public void delCacheChannel(String deviceId){
		if(StringUtils.isEmpty(deviceId))
			return;
		//删除缓存
		List<Channel> channelList=service.getChannelListByDevice(deviceId,null,null);
		if(!CollectionUtils.isEmpty(channelList)){
			channelList.forEach(p->{
				channelCache.removeCache(p.getDeviceId(),p.getChannelCode());
			});
		}
	}

    /**
     * 初始化通道
     * @param deviceId
     * @return
     */
    @Transactional
    public Boolean initPull(String deviceId){

		//协议中的通道号与虚拟通道号冲突，则不初始化
		List<ProtocolC> protocolCList=service.getRepeatChannelList(deviceId);
		if(!CollectionUtils.isEmpty(protocolCList)){
			List<String> repeatChannels=protocolCList.stream().map(ProtocolC::getChannelCode).collect(Collectors.toList());
			String repeatChannel=StringUtils.join(repeatChannels.toArray(),",");
			throw new BusinessException(202,"存在"+repeatChannel+"虚拟通道，请先处理");
		}

		delCacheChannel(deviceId);//删除缓存
        service.clearChannelByDeviceId(deviceId);
        service.initProtocolChannel(deviceId);

        //RePing设备，添加默认转译项
		DeviceExt deviceExt=deviceService.getDeviceById(deviceId);
		if(deviceExt!=null && !StringUtils.isEmpty(deviceExt.getStype()) && DeviceTypeEnum.REPING.getName().equals(deviceExt.getStype())){
			List<Channel> channels=service.getChannelListByDevice(deviceId,null,null);
			if(!CollectionUtils.isEmpty(channels)){
				Channel netChannel= channels.stream().filter(p-> "004".equals(p.getChannelCode())).findFirst().orElse(null);
				if(netChannel!=null){
					netChannel.setTranslate("0|正常,1|断开");
					updateTranslate(netChannel);

					netChannel.setNorvalue("正常");
					save(netChannel);
				}
			}
		}



        return true;
    }

//	/**
//	 * 添加虚拟通道
//	 * @param channel
//	 * @return
//	 */
//	@Transactional
//    public Channel addVirtual(Channel channel){
//        Virtual virtual=virtualService.findById(channel.getVirtualId());
//
//        if(virtual==null)
//            throw new BusinessException(202,"未找到虚拟通道");
//        //判断通道号是否已经存在
//        Channel codeChanelExist=service.getByDeviceIdandChannelCode(channel.getDeviceId(),channel.getChannelCode());
//        if(codeChanelExist!=null)
//            throw new BusinessException(203,"通道号已经存在");
//
//        channel.setName(virtual.getName());
//        channel.setAlarmData(ChannelDataEnum.REPORT.getId());
//        channel.setHistoryData(ChannelDataEnum.REPORT.getId());
//        channel.setXishu(new BigDecimal(1));
//
//        Channel c=super.save(channel);
//		channelCache.saveCache(c);//添加到缓存
//        return c;
//    }

	/**
	 * 还原通道名
	 * @param deviceId
	 * @return
	 */
	@Transactional
    public Boolean reductionChannelName(String deviceId){
		delCacheChannel(deviceId);//删除缓存
        service.reductionChannelName(deviceId);
        return true;
    }

    /**
     * 是否报警
     * @param c
     * @param showValue
     * @return
     */
	public Integer getAlarm(Channel c, String showValue) {
		showValue = showValue.trim();
		if(c == null || c.getDataType() == null || StringUtils.isEmpty(showValue))
			return 0;
		if(c.getDataType().equals(0)) {
			//模拟量
			try {
				BigDecimal v = new BigDecimal(showValue);
				if((c.getMax()!=null && v.compareTo(c.getMax())>0) || (c.getMin() != null && v.compareTo(c.getMin())<0))
					return 1;
				return 0;
			} catch (Exception e) {
				return 0;
			}
		}
		//开关量
		if(StringUtils.isEmpty(c.getNorvalue()))
			return 0;
		String[] ns = c.getNorvalue().split("\\|");
		for(String n:ns) {
			if(showValue.toLowerCase().equals(n.trim().toLowerCase()))
				return 0;
		}
		return 1;
	}

	/**
	 * 发送报警/报警恢复给远端设备
	 * @param device
	 * @param c
	 * @param data
	 */
	public void sendAlarmToItu(Device device, Channel c, CurrentData data) {
		try {
			if(c==null || c.getAlarmData() == null || c.getAlarmData().equals(0))
				return;
			CurrentData old = currentDataCache.getCurrentdatadetails(device.getDeviceCode(), c.getChannelCode());
			if(old!=null && old.getAlarm() != null && old.getAlarm().equals(0) && data.getAlarm().equals(0))
				return;
			if(data.getAlarm().equals(1)) {
				//发送报警 
				sendAlarmToServer(data,Command.ALARM,c);
			}else {
				//发送报警恢复
				sendAlarmToServer(data,Command.RECOVERY,c);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	/**
	 * 发送trap
	 * @param device
	 * @param c
	 * @param data
	 */
	public void sendTarpToItu(DeviceExt device, Channel c, CurrentData data) {
//		StringBuilder  sb = new StringBuilder();
//		sb.append("<OMMHISTORY>");
//		sb.append("<IP>"+deviceService.getDeviceIp(device.getDeviceCode())+"</IP>");
//		String resp = "<CH999>"
//				+ "<N>"+c.getName()+"</N>"
//				+ "<V>"+data.getShowValue()+"</V>"
//				+ "<U>"+data.getUnit()+"</U>"
//				+ "<AD>"+c.getDataType()+"</AD>"
//				+ "<AL>1</AL>"
//				+ "</CH999>";
//		sb.append(resp);
//		Settings set = settingsProcessor.findByName("serverId");
//		sb.append("<prold>"+(set != null?set.getValues():"")+"</prold>");
//		sb.append("</OMMHISTORY>");
//		sendConnectionProcessor.sendHistory("", sb.toString());
//		
		CurrentData da = new CurrentData();
		BeanUtils.copyProperties(data, da);
		da.setChannelCode("999");
		try {
			if(!device.getSendtrap().equals(1))
				return;
			if(data.getAlarm().equals(1)) {
				//发送报警 
				sendAlarmToServer(da,Command.ALARM,c);
			}else {
				//发送报警恢复
				sendAlarmToServer(da,Command.RECOVERY,c);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 得到协议通道列表
	 * @param deviceId
	 * @param virtualId
	 * @return
	 */
	public List<Channel> getChannelList(String deviceId,String searchStr){
		return service.getChannelListByDevice(deviceId,searchStr,false);
	}
	
	/**
	 * 通知报警给服务端
	 * @param alarm
	 * @param c 
	 */
	public void sendAlarmToServer(CurrentData alarm,String cmd, Channel c){
		DataViewAlarmOutDto dto = new DataViewAlarmOutDto();
		dto.setCH("CH"+this.service.getChannelCode(alarm.getChannelCode()));
		dto.setCommand(cmd);
		Settings set = settingsProcessor.findByName("serverId");
		dto.setID(set != null?set.getValues():"");
		dto.setProld(dto.getID());
		dto.setIP(deviceService.getDeviceIp(deviceCache.getDevice(alarm.getDeviceCode())));
//		Channel c = channelCache.getChannel(alarm.getDeviceId(), alarm.getChannelCode());
		if(c==null)
			return;
		dto.setName(c.getName());
		dto.setUnit(alarm.getUnit());
		dto.setValue(alarm.getShowValue());
		sendConnectionProcessor.sendAlarm(dto);
	}

	@Transactional
	@Override
	public Channel save(Channel reqDto) {
		Channel channel=super.save(reqDto);
		channelCache.saveCache(channel);
		return channel;
	}

	public PageRespDto<Channel> getPageChannelList(ChannelReqDto channelReqDto){
		PageRespDto<Channel> pageResp = new PageRespDto();
		PageHelper.startPage(channelReqDto.getPageInfo().getPageIndex(),channelReqDto.getPageInfo().getPageSize());
		Page<Channel> pm=(Page<Channel>) service.getChannelListByDevice(channelReqDto.getDeviceId(),channelReqDto.getSearchStr(),false);
		BeanUtils.copyProperties(pm, pageResp);
		pageResp.setDataList(pm.getResult());
		return pageResp;
	}
}